<?php
 
/**
 * Example:
 * $mail = new RedMVC\Mail();
 * $mail->addTo('test@test.de', 'tester');
 * $mail->addTo('test2@test2.de', 'tester2');
 * $mail->setFrom('stefan@test.de', 'stefan');
 * optional: $mail->addCc('test3@test3.de', 'tester3');
 * optional: $mail->addBcc('test4@test4.de', 'tester4'); 
 * $mail->setSubject('Das ist der Betreff');
 * $mail->setBodyText("Hallo, das ist der Body. (plain)");
 * optional: $mail->setBodyHtml("<p>Hallo, das ist der Body. (html)</p>");
 * optional: $mail->setPriority(RedMVC\Mail::MAIL_PRIORITY_HIGH); // 1-5
 * attachment: $mail->addAttachment(PUBLIC_PATH.'/images/help.png');
 * $mail->send();
 */

namespace RedMVC;

/**
 * Mail class
 *  
 * @category    RedMVC
 * @author      Jan Fischer, bitWorking <info@bitworking.de>
 */
class Mail{

    protected $_from;
    protected $_to                  = array();
    protected $_cc                  = array();
    protected $_bcc                 = array();
    
    protected $_subject             = '';
    protected $_bodyText;
    protected $_bodyHtml;

    protected $_attachments         = array();
    protected $_hasAttachments      = false;    
    
    protected $_header              = '';
    protected $_boundary            = '';
    protected $_body                = '';
    
    protected $_mailType            = 0;
    
    const MAIL_TYPE_PLAIN           = 0;
    const MAIL_TYPE_HTML            = 1;
    const MAIL_TYPE_MULTIPART       = 2;
    
    protected $_priority            = null;
    
    const MAIL_PRIORITY_HIGH        = 1;
    const MAIL_PRIORITY_MEDIUM_HIGH = 2;
    const MAIL_PRIORITY_NORMAL      = 3;
    const MAIL_PRIORITY_MEDIUM_LOW  = 4;
    const MAIL_PRIORITY_LOW         = 5;
    
    protected $_priorities          = array(
        0 => null,
        1 => array('1 (Highest)', 'High'),
        2 => array('2 (High)', 'Medium High'),
        3 => array('3 (Medium)', 'Normal'),
        4 => array('4 (Low)', 'Medium Low'),
        5 => array('5 (Lowest)', 'Low')
    );
    
    public function __construct(){
    
    }
    
    public function setFrom($email, $name = null){
        $this->_from = $this->_formatAddress($email, $name);
        return $this;
    }
    
    public function addTo($email, $name = null){
        $this->_to[] = $this->_formatAddress($email, $name);
        return $this;
    }
    
    public function addCc($email, $name = null){
        $this->_cc[] = $this->_formatAddress($email, $name);
        return $this;
    }
    
    public function addBcc($email, $name = null){
        $this->_bcc[] = $this->_formatAddress($email, $name);
        return $this;
    }
    
    public function setSubject($subject){
        $this->_subject = $subject;
        return $this;
    }
    
    public function setBodyText($bodyText){
        $this->_bodyText = $bodyText;
        return $this;
    }
    
    public function setBodyHtml($bodyHtml){
        $this->_bodyHtml = $bodyHtml;
        return $this;
    }
    
    public function addAttachment($attachment){    
        if(is_string($attachment)){
            $mailAttachment = new Mail\Attachment($attachment);
        }
        else if(is_object($attachment) && get_class($attachment) == 'RedMVC\Mail\Attachment'){
            $mailAttachment = $attachment;
        }
        if(null !== $mailAttachment->data){
            $this->_attachments[] = $mailAttachment;
        }
        return $this;
    }
    
    public function setPriority($priority = self::MAIL_PRIORITY_HIGH){
        $priority = min(max($priority, 1), 5);
        $this->_priority = $priority;
        return $this;
    }
    
    protected function _getType(){
        if(count($this->_attachments) > 0){
            $this->_hasAttachments = true;
        }
        // plain
        if(null !== $this->_bodyText && null === $this->_bodyHtml){
            $this->_mailType = self::MAIL_TYPE_PLAIN;
        }
        // html
        else if(null === $this->_bodyText && null !== $this->_bodyHtml){
            $this->_mailType = self::MAIL_TYPE_HTML;
        }
        // multipart
        else if(null !== $this->_bodyText && null !== $this->_bodyHtml){
            $this->_mailType = self::MAIL_TYPE_MULTIPART;
        }
    }
    
    protected function _getHeader(){
        // attachments
        if($this->_hasAttachments){
            $this->_boundary = $this->_getUniqueBoundary();
            $this->_header = "Mime-Version: 1.0\r\n";
            $this->_header .= "Content-Type: multipart/mixed; boundary=\"".$this->_boundary."\"\r\n";
        }
        // plain
        else if($this->_mailType === self::MAIL_TYPE_PLAIN){
            $this->_header = "Mime-Version: 1.0\r\n";
            $this->_header .= $this->_contentPlain();
        }
        // html
        else if($this->_mailType === self::MAIL_TYPE_HTML){
            $this->_header = "Mime-Version: 1.0\r\n";
            $this->_header .= $this->_contentHtml();
        }
        // multipart
        else if($this->_mailType === self::MAIL_TYPE_MULTIPART){
            $this->_boundary = $this->_getUniqueBoundary();
            $this->_header = "Mime-Version: 1.0\r\n";
            $this->_header .= "Content-Type: multipart/alternative; boundary=\"".$this->_boundary."\"\r\n";
        }
        // additional headers
        if(null !== $this->_from){
            $this->_header .= "From: ".$this->_from."\r\n";
        }
        if(count($this->_cc) > 0){
            $this->_header .= "Cc: ".implode(', ', $this->_cc)."\r\n";
        }
        if(count($this->_bcc) > 0){
            $this->_header .= "Bcc: ".implode(', ', $this->_bcc)."\r\n";
        }
        if(null !== $this->_priority){
            $this->_header .= "X-Priority: ".$this->_priorities[$this->_priority][0]."\r\n";
            $this->_header .= "X-MSMail-Priority: ".$this->_priorities[$this->_priority][1]."\r\n";
            $this->_header .= "Importance: ".$this->_priorities[$this->_priority][1]."\r\n";
        }
        $this->_header .= "X-Mailer: PHP/".phpversion();        
    }
    
    protected function _getBody(){
        // attachments
        if($this->_hasAttachments){
            // plain
            if($this->_mailType === self::MAIL_TYPE_PLAIN){
                $this->_body = "--".$this->_boundary."\r\n";
                $this->_body .= $this->_contentPlain();
                $this->_body .= "\r\n";
                $this->_body .= wordwrap($this->_bodyText, 70)."\r\n\r\n";
            }
            // html
            else if($this->_mailType === self::MAIL_TYPE_HTML){
                $this->_body .= "--".$this->_boundary."\r\n";
                $this->_body .= $this->_contentHtml();
                $this->_body .= "\r\n";
                $this->_body .= $this->_bodyHtml."\r\n\r\n";
            }
            // multipart
            else if($this->_mailType === self::MAIL_TYPE_MULTIPART){
                $boundary = $this->_getUniqueBoundary();
                $this->_body = "--".$this->_boundary."\r\n";
                $this->_body .= "Content-Type: multipart/alternative; boundary=\"".$boundary."\"\r\n\r\n";
                $this->_body .= "--".$boundary."\r\n";
                $this->_body .= $this->_contentPlain();
                $this->_body .= "\r\n";
                $this->_body .= wordwrap($this->_bodyText, 70)."\r\n\r\n";
                $this->_body .= "--".$boundary."\r\n";
                $this->_body .= $this->_contentHtml();
                $this->_body .= "\r\n";
                $this->_body .= $this->_bodyHtml."\r\n\r\n";
                $this->_body .= "--".$boundary."--\r\n\r\n";
            }
            // add attachments
            foreach($this->_attachments as $attachment){
                $this->_body .= "--".$this->_boundary."\r\n";
                $this->_body .= "Content-Disposition: attachment; filename=\"".$attachment->name."\";\r\n";
                $this->_body .= "Content-Length: ".$attachment->size.";\r\n";
                $this->_body .= "Content-Type: ".$attachment->type."; name=\"".$attachment->name."\"\r\n";
                $this->_body .= "Content-Transfer-Encoding: base64\r\n\r\n";
                $this->_body .= $attachment->data."\r\n"; 
            }
            $this->_body .= "--".$this->_boundary."--";
        }
        // plain
        else if($this->_mailType === self::MAIL_TYPE_PLAIN){
            $this->_body = wordwrap($this->_bodyText, 70);
        }
        // html
        else if($this->_mailType === self::MAIL_TYPE_HTML){
            $this->_body = $this->_bodyHtml;
        }
        // multipart
        else if($this->_mailType === self::MAIL_TYPE_MULTIPART){
            $this->_body = "--".$this->_boundary."\r\n";
            $this->_body .= $this->_contentPlain();
            $this->_body .= "\r\n";
            $this->_body .= wordwrap($this->_bodyText, 70)."\r\n\r\n";
            $this->_body .= "--".$this->_boundary."\r\n";
            $this->_body .= $this->_contentHtml();
            $this->_body .= "\r\n";
            $this->_body .= $this->_bodyHtml."\r\n\r\n";
            $this->_body .= "--".$this->_boundary."--";
        }
    }
    
    protected function _contentPlain(){
        $content = "Content-Type: text/plain; charset=iso-8859-1\r\n";
        $content .= "Content-Transfer-Encoding: quoted-printable\r\n";
        return $content;
    }
    
    protected function _contentHtml(){
        $content = "Content-Type: text/html; charset=iso-8859-1\r\n";
        $content .= "Content-Transfer-Encoding: quoted-printable\r\n";
        return $content;
    }
    
    protected function _formatAddress($email, $name){
        if(null === $name){
            return $email;
        }
        return "$name <$email>";
    }
    
    protected function _getUniqueBoundary(){
        return "PHP-alt-".uniqid();
    }
    
    public function send(){
        if(count($this->_to) == 0){
            throw new \Exception('Mail: No receiver added');
        }
    
        $this->_getType();
        $this->_getHeader();
        $this->_getBody();
    
        $to = implode(', ', $this->_to);

        return mail($to, $this->_subject, $this->_body, $this->_header);
    }
}